package fairygui.editor.pack
{
   public class MaxRectsPacker
   {
      
      private static var SIZE_SCHEME:Array;
       
      
      private var _maxRects:MaxRects;
      
      private var settings:PackSettings;
      
      public function MaxRectsPacker(param1:PackSettings)
      {
         super();
         this.settings = param1;
         this._maxRects = new MaxRects();
      }
      
      private static function initSizeScheme() : void
      {
         var _loc2_:int = 0;
         var _loc3_:int = 0;
         var _loc4_:int = 0;
         var _loc5_:int = 0;
         var _loc6_:Number = NaN;
         SIZE_SCHEME = new Array();
         var _loc1_:int = 5;
         while(_loc1_ <= 13)
         {
            _loc2_ = 5;
            while(_loc2_ <= 13)
            {
               _loc3_ = Math.pow(2,_loc1_);
               _loc4_ = Math.pow(2,_loc2_);
               _loc5_ = _loc3_ * _loc4_;
               _loc6_ = _loc3_ > _loc4_?Number(_loc3_ / _loc4_):Number(_loc4_ / _loc3_);
               SIZE_SCHEME.push({
                  "width":_loc3_,
                  "height":_loc4_,
                  "area":_loc5_,
                  "aspectRatio":_loc6_,
                  "len":Math.max(_loc3_,_loc4_)
               });
               _loc2_++;
            }
            _loc1_++;
         }
         SIZE_SCHEME.sort(compareSize);
      }
      
      private static function compareSize(param1:Object, param2:Object) : int
      {
         if(param1.len < param2.len)
         {
            return -1;
         }
         if(param1.len > param2.len)
         {
            return 1;
         }
         if(param1.area < param2.area)
         {
            return -1;
         }
         if(param1.area > param2.area)
         {
            return 1;
         }
         if(param1.aspectRatio < param2.aspectRatio)
         {
            return -1;
         }
         if(param1.aspectRatio > param2.aspectRatio)
         {
            return 1;
         }
         if(param1.width > param1.height)
         {
            return -1;
         }
         if(param2.width > param2.height)
         {
            return 1;
         }
         return 0;
      }
      
      public static function getNextPowerOfTwo(param1:Number) : int
      {
         var _loc2_:* = 0;
         if(param1 is int && param1 > 0 && (param1 & param1 - 1) == 0)
         {
            return param1;
         }
         _loc2_ = 1;
         param1 = param1 - 1.0e-9;
         while(_loc2_ < param1)
         {
            _loc2_ = _loc2_ << 1;
         }
         return _loc2_;
      }
      
      public function pack(param1:Vector.<NodeRect>) : Vector.<Page>
      {
         var _loc3_:NodeRect = null;
         var _loc4_:Vector.<Page> = null;
         var _loc5_:Page = null;
         if(this.settings.fast)
         {
            if(this.settings.rotation)
            {
               param1.sort(this.compareNodeRect);
            }
            else
            {
               param1.sort(this.compareNodeRect2);
            }
         }
         var _loc2_:int = this.settings.padding;
         for each(_loc3_ in param1)
         {
            if(this.settings.maxWidth - _loc3_.width > _loc2_)
            {
               _loc3_.width = _loc3_.width + _loc2_;
            }
            if(this.settings.maxHeight - _loc3_.height > _loc2_)
            {
               _loc3_.height = _loc3_.height + _loc2_;
            }
         }
         _loc4_ = new Vector.<Page>();
         while(param1.length > 0)
         {
            _loc5_ = this.packPage(param1);
            if(_loc5_ == null)
            {
               return null;
            }
            if(this.settings.pot)
            {
               _loc5_.width = getNextPowerOfTwo(_loc5_.width);
               _loc5_.height = getNextPowerOfTwo(_loc5_.height);
            }
            if(this.settings.square)
            {
               _loc5_.width = Math.max(_loc5_.width,_loc5_.height);
               _loc5_.height = Math.max(_loc5_.width,_loc5_.height);
            }
            _loc4_.push(_loc5_);
            param1 = _loc5_.remainingRects;
         }
         _loc4_.sort(this.comparePage);
         for each(_loc5_ in _loc4_)
         {
            for each(_loc3_ in _loc5_.outputRects)
            {
               if(!_loc3_.rotated)
               {
                  if(this.settings.maxWidth - _loc3_.width > _loc2_)
                  {
                     _loc3_.width = _loc3_.width - _loc2_;
                  }
                  if(this.settings.maxHeight - _loc3_.height > _loc2_)
                  {
                     _loc3_.height = _loc3_.height - _loc2_;
                  }
               }
               else
               {
                  if(this.settings.maxHeight - _loc3_.width > _loc2_)
                  {
                     _loc3_.width = _loc3_.width - _loc2_;
                  }
                  if(this.settings.maxWidth - _loc3_.height > _loc2_)
                  {
                     _loc3_.height = _loc3_.height - _loc2_;
                  }
               }
            }
            for each(_loc3_ in _loc5_.remainingRects)
            {
               if(!_loc3_.rotated)
               {
                  if(this.settings.maxWidth - _loc3_.width > _loc2_)
                  {
                     _loc3_.width = _loc3_.width - _loc2_;
                  }
                  if(this.settings.maxHeight - _loc3_.height > _loc2_)
                  {
                     _loc3_.height = _loc3_.height - _loc2_;
                  }
               }
               else
               {
                  if(this.settings.maxHeight - _loc3_.width > _loc2_)
                  {
                     _loc3_.width = _loc3_.width - _loc2_;
                  }
                  if(this.settings.maxWidth - _loc3_.height > _loc2_)
                  {
                     _loc3_.height = _loc3_.height - _loc2_;
                  }
               }
            }
         }
         return _loc4_;
      }
      
      private function packPage(param1:Vector.<NodeRect>) : Page
      {
         var _loc7_:Object = null;
         var _loc8_:int = 0;
         var _loc10_:Page = null;
         var _loc11_:int = 0;
         var _loc12_:int = 0;
         var _loc13_:NodeRect = null;
         var _loc14_:Page = null;
         var _loc15_:int = 0;
         var _loc16_:int = 0;
         var _loc17_:BinarySearch = null;
         var _loc18_:int = 0;
         var _loc19_:BinarySearch = null;
         var _loc20_:BinarySearch = null;
         var _loc21_:Page = null;
         if(SIZE_SCHEME == null)
         {
            initSizeScheme();
         }
         var _loc2_:int = 0;
         if(this.settings.edgePadding && !this.settings.duplicatePadding)
         {
            _loc2_ = this.settings.padding;
         }
         var _loc3_:int = 0;
         var _loc4_:int = param1.length;
         var _loc5_:int = 0;
         while(_loc5_ < _loc4_)
         {
            _loc13_ = param1[_loc5_];
            _loc3_ = _loc3_ + _loc13_.width * _loc13_.height;
            _loc5_++;
         }
         var _loc6_:Array = new Array();
         for each(_loc7_ in SIZE_SCHEME)
         {
            if(_loc7_.area >= _loc3_ && _loc7_.width <= this.settings.maxWidth && _loc7_.height <= this.settings.maxHeight)
            {
               _loc6_.push(_loc7_);
            }
         }
         _loc8_ = _loc6_.length;
         if(_loc8_ == 0)
         {
            _loc6_.push({
               "width":this.settings.maxWidth,
               "height":this.settings.maxHeight
            });
            _loc8_ = 1;
         }
         var _loc9_:Page = null;
         _loc5_ = 0;
         while(_loc5_ < _loc8_)
         {
            _loc11_ = _loc6_[_loc5_].width;
            _loc12_ = _loc6_[_loc5_].height;
            _loc9_ = this.packAtSize(_loc5_ != _loc8_ - 1,_loc11_ - _loc2_,_loc12_ - _loc2_,param1);
            if(_loc9_ != null)
            {
               break;
            }
            _loc5_++;
         }
         if(_loc9_ != null && !this.settings.pot && _loc9_.remainingRects.length == 0)
         {
            if(this.settings.square)
            {
               _loc15_ = Math.min(_loc11_ / 2,_loc12_ / 2);
               _loc16_ = Math.max(_loc11_,_loc12_);
               _loc17_ = new BinarySearch(_loc15_,_loc16_,!!this.settings.fast?25:15,this.settings.pot);
               _loc18_ = _loc17_.reset();
               while(_loc18_ != -1)
               {
                  _loc10_ = this.packAtSize(true,_loc18_ - _loc2_,_loc18_ - _loc2_,param1);
                  _loc14_ = this.getBest(_loc14_,_loc10_);
                  _loc18_ = _loc17_.next(_loc10_ == null);
               }
            }
            else
            {
               _loc19_ = new BinarySearch(_loc11_ / 2,_loc11_,!!this.settings.fast?25:15,this.settings.pot);
               _loc20_ = new BinarySearch(_loc12_ / 2,_loc12_,!!this.settings.fast?25:15,this.settings.pot);
               _loc11_ = _loc19_.reset();
               _loc12_ = _loc20_.reset();
               while(true)
               {
                  _loc21_ = null;
                  while(_loc11_ != -1)
                  {
                     _loc10_ = this.packAtSize(true,_loc11_ - _loc2_,_loc12_ - _loc2_,param1);
                     _loc21_ = this.getBest(_loc21_,_loc10_);
                     _loc11_ = _loc19_.next(_loc10_ == null);
                  }
                  _loc14_ = this.getBest(_loc14_,_loc21_);
                  _loc12_ = _loc20_.next(_loc21_ == null);
                  if(_loc12_ == -1)
                  {
                     break;
                  }
                  _loc11_ = _loc19_.reset();
               }
            }
            if(_loc14_ != null)
            {
               _loc9_ = _loc14_;
            }
         }
         return _loc9_;
      }
      
      private function packAtSize(param1:Boolean, param2:int, param3:int, param4:Vector.<NodeRect>) : Page
      {
         var _loc8_:int = 0;
         var _loc9_:int = 0;
         var _loc10_:int = 0;
         var _loc12_:Page = null;
         var _loc13_:Vector.<NodeRect> = null;
         var _loc5_:Page = null;
         var _loc6_:Array = MaxRects.AllMethods;
         var _loc7_:int = _loc6_.length;
         var _loc11_:int = param4.length;
         _loc9_ = 0;
         while(_loc9_ < _loc7_)
         {
            _loc8_ = _loc6_[_loc9_];
            this._maxRects.init(param2,param3,this.settings.rotation);
            if(!this.settings.fast)
            {
               _loc12_ = this._maxRects.pack(param4,_loc6_[_loc9_]);
            }
            else
            {
               _loc13_ = new Vector.<NodeRect>();
               _loc10_ = 0;
               while(_loc10_ < _loc11_)
               {
                  if(this._maxRects.insert(param4[_loc10_],_loc8_) == null)
                  {
                     while(_loc10_ < _loc11_)
                     {
                        _loc13_.push(param4[_loc10_++]);
                     }
                  }
                  _loc10_++;
               }
               _loc12_ = this._maxRects.getResult();
               _loc12_.remainingRects = _loc13_;
            }
            if(!(param1 && _loc12_.remainingRects.length > 0))
            {
               if(_loc12_.outputRects.length != 0)
               {
                  _loc5_ = this.getBest(_loc5_,_loc12_);
               }
            }
            _loc9_++;
         }
         return _loc5_;
      }
      
      private function getBest(param1:Page, param2:Page) : Page
      {
         if(param1 == null)
         {
            return param2;
         }
         if(param2 == null)
         {
            return param1;
         }
         return param1.occupancy > param2.occupancy?param1:param2;
      }
      
      private function comparePage(param1:Page, param2:Page) : int
      {
         return param2.outputRects.length - param1.outputRects.length;
      }
      
      private function compareNodeRect(param1:NodeRect, param2:NodeRect) : int
      {
         var _loc3_:int = param1.width > param1.height?int(param1.width):int(param1.height);
         var _loc4_:int = param2.width > param2.height?int(param2.width):int(param2.height);
         return _loc4_ - _loc3_;
      }
      
      private function compareNodeRect2(param1:NodeRect, param2:NodeRect) : int
      {
         return param2.width - param1.width;
      }
   }
}
